//
//  Emoticon.swift
//  表情键盘
//
//  Created by waterfoxjie on 15/8/9.
//  Copyright © 2015年 zj. All rights reserved.
//

import UIKit

/**

1、Emoticons.bundle的目录中有一个emoticons.plist文件，packages数组中的每一项字典的id对应的时每一套表情的目录名

2、每一个表情目录下，都有一个info.plist文件，group_name_cn记录表情包的名字，emoticons数组，记录着整套表情的数组

3、表情字典信息：
   
   chs  ： 定义的是发布微博以及网络传输使用的微博传输字符串
   png  ： 在客户端显示的图片名称
   code ： emoji要显示的16进制字符串

*/

// MARK: - 表情包模型
class EmoticonPackage: NSObject {
    
    // MARK: - 定义属性
    // 目录名
    var id : String
    
    // 分组名
    var groupName : String = ""
    
    // 表情数组
    var emoticons : [Emoticon]?
    
    // MARK: - 构造函数
    init(id : String , groupName : String = "") {
        
        // 赋值
        self.id = id
        
        self.groupName = groupName
        
    }
    
    // MARK: - 提取string中的表情字符串
    // 将string生成带表情的属性字符串
    class func emoticonText(string : String , font : UIFont) -> NSAttributedString {
    
        // 提取string中的表情字符串 -- 正则表达式
        // 正则表达式中，[]是关键字，需要用\\进行转义
        let pattern = "\\[.*?\\]"
        
        let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators)
        
        // 开始匹配，返回一个数组
        /// 第二种匹配方式 ：matchesInString（在字符串中做任意多得匹配）
        let results = regex.matchesInString(string, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, string.characters.count))
        
        // 获取匹配的结果数量
        var count = results.count
        
        // 使用string创建属性文本
        let strM = NSMutableAttributedString(string: string)
        
        // 遍历数组，获取匹配结果，注意的是，这里需要反序遍历，因为正序遍历的话，后面表情符号的range会发生变化
        while count > 0 {
            
            // 匹配结果
            let result = results[--count]
            
            // 获取字符串
            let range = result.rangeAtIndex(0)
            
            let emString = (string as NSString).substringWithRange(range)
            
            // 根据字符串获得表情
            if let emoticon = emoticon(string: emString) {
                
                let attString = EmoticonAttachment.imgText(emoticon, font: font)
                
                // 替换strM中对应位置的文本
                strM.replaceCharactersInRange(range, withAttributedString: attString)
                
            }
        }
        
        // 更新整个字符串字体
        strM.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, strM.length))
        
        return strM

    }
    
    
    // MARK: - 返回对应的表情符号
    // 根据字符串返回对应的表情符号函数，为了与属性等进行区分，传参数时给参数加一个参数名，调用的时候就不会乱了
    private class func emoticon(string string : String) -> Emoticon? {
        
        var emoticon : Emoticon? = nil
        
        // 遍历所有的表情包中的表情
        for emPackage in EmoticonPackage.packages {
            
            // 拿到表情包之后，在数组中查找表情 -- 使用谓词
            // .last : 取获取到得最后数组的最后一个元素，就是我们想要的表情符
            //            emoticon = emPackage.emoticons!.filter({ (em) -> Bool in
            //
            //                return em.chs == string
            //
            //            }).last
            /// 以上代码可简写为：小括号也可以去掉
            emoticon = emPackage.emoticons!.filter{
                
                $0.chs == string
                
                }.last
            
            // 判断是否获取到了
            if emoticon != nil {
                
                break
            }
        }
        
        return emoticon
    }
    
    // MARK: - 添加最近使用表情
    class func addFavorate(emoticon : Emoticon) {
        
        // 判断是否是删除按钮，是则直接删除
        if emoticon.removeEmoticon {
            
            return
        }
    
        // 拿到第0个分组
        var ems = packages[0].emoticons
        
        /// 解决当添加到一定数量时，删除按钮不见的bug，首先先删除末尾的删除按钮，在添加完表情之后，再在末尾添加删除按钮
        ems?.removeLast()
        
        // 添加到数组中
        /// 添加是出现重复的表情   解决：先判断数组中是否有重复的表情
        let contains = ems!.contains(emoticon)
        
        // 当有重复的表情时，删除原来的，将表情添加到数组下标为0的位置
        if contains {
        
            // 获取原来元素的位置
            let index = ems?.indexOf(emoticon)
            
            // 删除当前下标下的元素
            ems?.removeAtIndex(index!)
            
            print(index)
            
            // 将这个元素重新添加到数组的首位
            ems?.insert(emoticon, atIndex: 0)
            
        } else {
        
            // 没有重复表情的情况下，直接添加到数组首位
            ems?.insert(emoticon, atIndex: 0)
            
            // 删除末尾元素
            ems?.removeLast()

        }
        
        /// 重新添加删除按钮
        ems?.append(Emoticon(remove: true))
        
        // 重新设置
        packages[0].emoticons = ems
        
    }
    
    // MARK: - 使用单例加载表情包
    /// 解决表情包会被重复加载的bug   static ：静态，只允许被设置一次数值
    static let packages = EmoticonPackage.loadPackage()
    
    // 加载所有表情包
    private class func loadPackage() -> [EmoticonPackage] {
        
        // 加载emoticons.plist路径
        let path = bundlePath.stringByAppendingPathComponent("emoticons.plist")
        
        // 加载emoticons.plist
        let dict = NSDictionary(contentsOfFile: path)!
        
        // 拿到package数组
        let array = dict["packages"] as! [[String : AnyObject]]
        
        var arrayM = [EmoticonPackage]()
        
        // 添加最近分组
        let package = EmoticonPackage(id: "", groupName: "最近").appendEmptrEmotions()
        
        arrayM.append(package)
        
        // 遍历数组
        for d in array {
        
            // 链式响应
            let package = EmoticonPackage(id: d["id"] as! String).loadEmoticons().appendEmptrEmotions()
            
            arrayM.append(package)
        }
        
        return arrayM
    }
    
    // MARK: - 加载当前对象对应的表情数组
    // Self ：返回Self表示返回本类的对象
    private func loadEmoticons() -> Self {
        
        // 获取路径
        let path = EmoticonPackage.bundlePath.stringByAppendingPathComponent(id).stringByAppendingPathComponent("info.plist")
        
        let dict = NSDictionary(contentsOfFile: path)!
        
        // 拿到group_name_cn（分组名称）
        groupName = dict["group_name_cn"] as! String
        
        // 拿到emoticons这个表情数组
        let array = dict["emoticons"] as! [[String : String]]
        
        // 遍历数组
        emoticons = [Emoticon]()
        
        // 计数器
        var index = 0
        
        for d in array {
        
            // 这样就能返回一个id属性的值
            emoticons?.append(Emoticon(id: id, dict: d))
            
            index++
            
            // 当前是第20个按钮时，添加一个删除按钮
            if index == 20 {
            
                emoticons?.append(Emoticon(remove: true))
                
                index = 0
            }
        }
    
        return self
    }
    
    // MARK: - 判断是不是整页显示
    private func appendEmptrEmotions() -> Self {
        
        // 判断表情包是否存在
        if emoticons == nil {
        
            // 创建一个
            emoticons = [Emoticon]()
            
        }
    
        let count = emoticons!.count % 21
        
        // count = 0 的时候表示现在是整页，不用添加
        // emoticons?.count == 0 表示当前的表情包是默认表情包，什么都没有，添加空白充当占位符
        if count > 0 || emoticons?.count == 0 {
        
            // 如果不是整页显示的，遍历添加空格
            for _ in count..<20 {
                
                emoticons?.append(Emoticon(remove: false))
            }
            
            // 最后再添加一个删除按钮
            emoticons?.append(Emoticon(remove: true))
        }
        
        return self
    }
    
    // MARK: - 加载Emoticons.bundle的路径
    private static let bundlePath = NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent("Emoticons.bundle")
    
}


// MARK: - 表情模型
class Emoticon: NSObject {
    
    // MARK: - 定义属性
    // 给服务器的表情文字
    var chs : String?
    
    // 本地显示的图片文件名
    var png : String?
    
    // emoji中的表情属性（16进制数形式）
    var code : String? {
    
        didSet {
        
            // 扫描器
            let scanner = NSScanner(string: code!)
            
            var value : UInt32 = 0
            
            scanner.scanHexInt(&value)
            
            emoji = String(Character(UnicodeScalar(value)))
        }
    }
    
    // emoji字符串
    var emoji : String?
    
    // 定义一个id属性
    var id : String?
    
    // 图片完整路径（Emoticons.bundle的路径 + id + png）
    var imagePath : String {
        
        // 判断是否是图片表情
        if chs == nil {
        
            return ""
        }
        
        return EmoticonPackage.bundlePath.stringByAppendingPathComponent(id!).stringByAppendingPathComponent(png!)
        
    }
    
    // 定义删除表情的标记
    var removeEmoticon = false
    
    // 定义一个表情使用次数
    var times = 0
    
    // 构造函数
    init(remove : Bool) {
    
        removeEmoticon = remove
    }
    
    init(id : String , dict : [String : String]) {
        
        self.id = id
    
        super.init()
        
        setValuesForKeysWithDictionary(dict)
    }
    
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
    
    override var description : String {
        
        return "\(chs) \(png) \(code)"
    }
    
    
    

}
